﻿using UnityEngine;

namespace winS.Unity.Geometry
{
    /// <summary>
    /// 矩形(OBB)
    /// </summary>
    public readonly struct Rect
    {
        public float halfWidth => width * 0.5f;
        public float halfHeight => height * 0.5f;

        public Vector2 size => new Vector2(width, height);
        public Vector2 center => new Vector2(x, y);
        public Vector2 topLeftPoint => center - rightDirection * halfWidth + upDirection * halfHeight;
        public Vector2 topRightPoint => center + rightDirection * halfWidth + upDirection * halfHeight;
        public Vector2 bottomLeftPoint => center - rightDirection * halfWidth - upDirection * halfHeight;
        public Vector2 bottomRightPoint => center + rightDirection * halfWidth - upDirection * halfHeight;

        public readonly float x { get; }
        public readonly float y { get; }
        public readonly float angle { get; }
        public readonly float width { get; }
        public readonly float height { get; }
        public readonly Vector2 upDirection { get; }
        public readonly Vector2 rightDirection { get; }

        public static Rect CreateByTopLeftPoint(Vector2 topLeftPoint, Vector2 size, Vector2 rightDirection)
        {
            return new Rect(topLeftPoint - 0.5f * size.y * VectorUtility.VerticalDirectionLeft(rightDirection) + 0.5f * size.x * rightDirection, size, rightDirection);
        }
        public static Rect CreateByTopRightPoint(Vector2 topRightPoint, Vector2 size, Vector2 rightDirection)
        {
            return new Rect(topRightPoint - 0.5f * size.y * VectorUtility.VerticalDirectionLeft(rightDirection) - 0.5f * size.x * rightDirection, size, rightDirection);
        }
        public static Rect CreateByBottomLeftPoint(Vector2 bottomLeftPoint, Vector2 size, Vector2 rightDirection)
        {
            return new Rect(bottomLeftPoint + 0.5f * size.y * VectorUtility.VerticalDirectionLeft(rightDirection) + 0.5f * size.x * rightDirection, size, rightDirection);
        }
        public static Rect CreateByBottomRightPoint(Vector2 bottomRightPoint, Vector2 size, Vector2 rightDirection)
        {
            return new Rect(bottomRightPoint + 0.5f * size.y * VectorUtility.VerticalDirectionLeft(rightDirection) - 0.5f * size.x * rightDirection, size, rightDirection);
        }

        public Rect(float x, float y, Vector2 size) : this(x, y, size.x, size.y, Vector2.right)
        {
        }
        public Rect(float x, float y, float width, float height) : this(x, y, width, height, Vector2.right)
        {
        }
        public Rect(float x, float y, float width, float height, Vector2 rightDirection)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.rightDirection = rightDirection;
            angle = VectorUtility.Angle(Vector2.right, rightDirection, AngleRangeType.FullRange);
            upDirection = VectorUtility.VerticalDirectionLeft(rightDirection);
        }
        public Rect(Vector2 center, Vector2 size) : this(center.x, center.y, size.x, size.y, Vector2.right)
        {
        }
        public Rect(Vector2 center, Vector2 size, Vector2 rightDirection) : this(center.x, center.y, size.x, size.y, rightDirection)
        {
        }
        public Rect(Vector2 center, float width, float height) : this(center.x, center.y, width, height, Vector2.right)
        {
        }
        public Rect(Vector2 center, float width, float height, Vector2 rightDirection) : this(center.x, center.y, width, height, rightDirection)
        {
        }

        /// <summary>
        /// 是否包含点 <paramref name="point"/>.
        /// 如果当前矩形包含 <paramref name="point"/> 返回 true
        /// </summary>
        public bool Contains(Vector2 point)
        {
            point -= bottomLeftPoint;
            float cos = Math.CosDeg(-angle);
            float sin = Math.SinDeg(-angle);
            float x = cos * point.x - sin * point.y;
            if (x < 0 || x > width) return false;
            float y = sin * point.x + cos * point.y;
            if (y < 0 || y > height) return false;
            return true;
        }

        /// <summary>
        /// 是否与矩形 <paramref name="rect"/> 重叠
        /// </summary>
        public bool Overlap(Rect rect)
        {
            throw new System.NotImplementedException();
        }
        /// <summary>
        /// 是否与圆形 <paramref name="circle"/> 重叠
        /// </summary>
        public bool Overlap(Circle circle)
        {
            //参考文章 https://www.zhihu.com/question/24251545/answer/27184960

            //圆心点转到矩形坐标系下
            Vector2 origin = circle.center - center;
            float cos = Math.CosDeg(-angle);
            float sin = Math.SinDeg(-angle);

            //映射到第一象限
            origin = new Vector2(Math.Abs(cos * origin.x - sin * origin.y), Math.Abs(sin * origin.x + cos * origin.y));

            //得到第一象限下圆心到矩形的最短距离
            Vector2 vector = origin - new Vector2(halfWidth, halfHeight);
            if (vector.x < 0) vector.x = 0;
            if (vector.y < 0) vector.y = 0;

            return vector.sqrMagnitude < circle.radius * circle.radius;
        }
    }
}